package com.hellohoper.assembly.common.utils.util;

/**
 * Created by hk on 9/30/16.
 */

import com.dyuproject.protostuff.LinkedBuffer;
import com.dyuproject.protostuff.ProtostuffIOUtil;
import com.dyuproject.protostuff.Schema;
import com.dyuproject.protostuff.runtime.RuntimeSchema;
import org.objenesis.Objenesis;
import org.objenesis.ObjenesisStd;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

public class SerializableUtils {

    private static Map<Class<?>, Schema<?>> cachedSchema = new ConcurrentHashMap();

    private static Objenesis objenesis = new ObjenesisStd(true);

    private SerializableUtils() {
        throw new IllegalAccessError("Utility class");
    }

    private static <T> Schema<T> getSchema(Class<T> clazz) {
        Schema schema = (Schema) cachedSchema.get(clazz);
        if (schema == null) {
            schema = RuntimeSchema.getSchema(clazz);
            if (schema != null) {
                cachedSchema.put(clazz, schema);
            }
        }

        return schema;
    }

    public static <T> byte[] serialize(T obj) throws IOException {
        if (obj == null) {
            throw new IllegalArgumentException("serialize argument is illegal");
        } else {
            Schema schema = getSchema(obj.getClass());
            if (schema == null) {
                throw new RuntimeException("can not get schema, object not suppot");
            } else {
                LinkedBuffer buffer = LinkedBuffer.allocate(512);
                ByteArrayOutputStream bos = null;

                byte[] bytes1;
                try {
                    bos = new ByteArrayOutputStream();
                    ProtostuffIOUtil.writeTo(bos, obj, schema, buffer);
                    bytes1 = bos.toByteArray();
                } catch (IOException var12) {
                    throw var12;
                } finally {
                    buffer.clear();

                    try {
                        if (bos != null) {
                            bos.close();
                        }
                    } catch (IOException var13) {
                        throw var13;
                    }

                }

                return bytes1;
            }
        }
    }

    public static <T> T deserialize(byte[] data, Class<T> clazz) {
        if (data != null && data.length > 0 && clazz != null) {
            Object result = objenesis.newInstance(clazz);
            Schema schema = getSchema(clazz);
            ProtostuffIOUtil.mergeFrom(data, result, schema);
            return (T) result;
        } else {
            throw new IllegalArgumentException("deserialize argument is illegal");
        }
    }

    public static <T> byte[] serializeList(List<T> objList) throws IOException {
        if (objList != null && objList.size() > 0 && !objList.isEmpty()) {
            Schema schema = getSchema(objList.get(0).getClass());
            LinkedBuffer buffer = LinkedBuffer.allocate(512);
            ByteArrayOutputStream bos = null;

            byte[] bytes1;
            try {
                bos = new ByteArrayOutputStream();
                ProtostuffIOUtil.writeListTo(bos, objList, schema, buffer);
                bytes1 = bos.toByteArray();
            } catch (IOException var12) {
                throw var12;
            } finally {
                buffer.clear();

                try {
                    if (bos != null) {
                        bos.close();
                    }
                } catch (IOException var13) {
                    throw var13;
                }

            }

            return bytes1;
        } else {
            throw new IllegalArgumentException("serialize argument is illegal");
        }
    }

    public static <T> List<T> deserializeList(byte[] bytes, Class<T> clazz) throws IOException {
        if (bytes != null && bytes.length > 0 && clazz != null) {
            List result = null;

            try {
                Schema e = getSchema(clazz);
                result = ProtostuffIOUtil.parseListFrom(new ByteArrayInputStream(bytes), e);
                return result;
            } catch (IOException var4) {
                throw var4;
            }
        } else {
            throw new IllegalArgumentException("deserialize argument is illegal");
        }
    }

    public static <T> byte[] serializeSet(Set<T> objSet) throws IOException {
        ArrayList list = new ArrayList();
        Iterator iterator = objSet.iterator();

        while (iterator.hasNext()) {
            list.add(iterator.next());
        }

        Object bytes = null;

        try {
            byte[] bytes1 = serializeList(list);
            return bytes1;
        } catch (IOException var5) {
            throw var5;
        }
    }

    public static <T> Set<T> deserializeSet(byte[] bytes, Class<? extends Set> objSet, Class<T> clazz) throws InstantiationException, IllegalAccessException, IOException {
        List result;
        Set set;

        try {
            set = (Set) objSet.newInstance();
            result = deserializeList(bytes, clazz);
        } catch (InstantiationException var7) {
            throw var7;
        } catch (IllegalAccessException var8) {
            throw var8;
        } catch (IOException var9) {
            throw var9;
        }

        Iterator e = result.iterator();

        while (e.hasNext()) {
            Object t = e.next();
            set.add(t);
        }

        return set;
    }

    public static <K, V> byte[] serializeMap(Map<K, V> objMap) throws IOException {
        ArrayList keyList = new ArrayList();
        ArrayList valList = new ArrayList();
        Iterator keyBytes = objMap.entrySet().iterator();

        Entry valBytes;
        while (keyBytes.hasNext()) {
            valBytes = (Entry) keyBytes.next();
            keyList.add(valBytes.getKey());
            valList.add(valBytes.getValue());
        }

        byte[] keyBytes1;
        byte[] valBytes1;
        try {
            keyBytes1 = serializeList(keyList);
            valBytes1 = serializeList(valList);
        } catch (IOException var6) {
            throw var6;
        }

        ByteBuffer byteBuffer = ByteBuffer.allocate(keyBytes1.length + valBytes1.length + 4 + 4 + 2);
        byteBuffer.putInt(keyBytes1.length);
        byteBuffer.put(keyBytes1);
        byteBuffer.putInt(valBytes1.length);
        byteBuffer.put(valBytes1);
        return byteBuffer.array();
    }

    public static <K, V> Map<K, V> deserializeMap(byte[] bytes, Class<? extends Map> objMap, Class<K> keyClazz, Class<V> valClazz) throws InstantiationException, IllegalAccessException, IOException {
        ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length);
        byteBuffer.put(bytes);
        int keyLen = byteBuffer.getInt(0);
        byte[] keyBytes = new byte[keyLen];

        int valLen;
        for (valLen = 0; valLen < keyLen; ++valLen) {
            keyBytes[valLen] = bytes[4 + valLen];
        }

        valLen = byteBuffer.getInt(4 + keyLen);
        byte[] valBytes = new byte[valLen];

        for (int keyResult = 0; keyResult < valLen; ++keyResult) {
            valBytes[keyResult] = bytes[4 + keyLen + 4 + keyResult];
        }

        List var16;
        List valResult;
        Map map;

        try {
            map = (Map) objMap.newInstance();
            var16 = deserializeList(keyBytes, keyClazz);
            valResult = deserializeList(valBytes, valClazz);
        } catch (InstantiationException var13) {
            throw var13;
        } catch (IllegalAccessException var14) {
            throw var14;
        } catch (IOException var15) {
            throw var15;
        }

        if (var16.size() != valResult.size()) {
            throw new RuntimeException();
        } else {
            for (int i = 0; i < var16.size(); ++i) {
                map.put(var16.get(i), valResult.get(i));
            }

            return map;
        }
    }
}
